package org.dftproject.genesis.core.http;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.PlainSocketFactory;
import org.apache.http.conn.Scheme;
import org.apache.http.conn.SchemeRegistry;
import org.apache.http.conn.params.HttpConnectionManagerParams;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
import org.dftproject.genesis.core.Activator;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.SynchronousBundleListener;

public class HttpManager {

	private static final Log log = LogFactory.getLog(HttpManager.class);

	public final static String USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0)";// "Genesis/0.1
	// (+http://www.dftproject.org/wiki/Genesis)";

	public final static int URGENT_SO_TIMEOUT = 15000;
	public final static int URGENT_CONNECTION_TIMEOUT = 15000;

	public final static int SO_TIMEOUT = 30000;
	public final static int CONNECTION_TIMEOUT = 60000;

	private final HttpClient httpClient;
	private LocalHttpCache cache;

	private static final HttpManager singleton = new HttpManager();

	public static HttpManager getDefault() {
		return singleton;
	}

	private HttpManager() {
		HttpParams params = new BasicHttpParams();
		HttpConnectionManagerParams.setMaxTotalConnections(params, 100);
		HttpConnectionManagerParams.setDefaultMaxConnectionsPerHost(params, 2);
		HttpProtocolParams.setUserAgent(params, USER_AGENT);
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, "UTF-8");

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

		ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
		httpClient = new DefaultHttpClient(cm, params);

		cache = new LocalHttpCache(getCachePath());

		Activator.getDefault().getBundle().getBundleContext().addBundleListener(new SynchronousBundleListener() {

			public void bundleChanged(BundleEvent event) {
				if (event.getType() == BundleEvent.STOPPING)
					close();
			}

		});
	}

	protected void close() {
		if (cache != null) {
			log.info("Closing the HTTP manager...");
	
			cache.close();
			cache = null;
		}
	}

	public String getCachePath() {
		return Platform.getInstanceLocation().getURL().getPath().substring(1) + "http/cache";
	}

	public String getWebPage(String url) {
		if (cache == null)
			return null;
		
		String data = cache.getResponse(url);
		if (data != null)
			return data;

		HttpGet httpGet = null;
		HttpEntity entity = null;
		try {
			log.info("Downloading " + url + "...");

			httpGet = new HttpGet(url);
			HttpResponse response = httpClient.execute(httpGet);
			
			entity = response.getEntity();
			if (entity != null) {
				data = EntityUtils.toString(entity);
				cache.putResponse(url, data);
			}
		} catch (IOException e) {
			log.error("Failed to download " + url + ": " + e.getLocalizedMessage());
		} catch (Exception e) {
			if (httpGet != null)
				httpGet.abort();
			log.error("Failed to download " + url + ": " + e.getLocalizedMessage());
		} finally {
			try {
				if (entity != null)
					entity.consumeContent();
			} catch (IOException e) {
			}
		}

		return data;
	}

	public String getRedirect(String url) {
		if (cache == null)
			return null;
		
		HttpGet httpGet = null;
		HttpEntity entity = null;
		try {
			log.info("Getting redirect from " + url + "...");

			httpGet = new HttpGet(url);
			HttpClientParams.setRedirecting(httpGet.getParams(), false);

			HttpResponse response = httpClient.execute(httpGet);

			entity = response.getEntity();

			for (Header header : response.getHeaders("location"))
				return header.getValue();
		} catch (IOException e) {
			log.error("Failed to get redirect from " + url + ": " + e.getLocalizedMessage());
		} catch (Exception e) {
			if (httpGet != null)
				httpGet.abort();
			log.error("Failed to get redirect from " + url + ": " + e.getLocalizedMessage());
		} finally {
			try {
				if (entity != null)
					entity.consumeContent();
			} catch (IOException e) {
			}
		}

		return null;
	}

}
